package cn.net.cfss.fgbp.auth.util;

import cn.net.cfss.fgbp.auth.vo.Captcha;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.BASE64Encoder;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Random;

/**
 * @author wutao
 * @version 1.0
 * @date 2020/4/21 20:25
 */
public class SliderCheckUtil {
    private static final Logger logger = LoggerFactory.getLogger(SliderCheckUtil.class);

    static int targetLength=55;//小图长
    static int targetWidth=45;//小图宽
    static int circleR=6;//半径
    static int r1=3;//距离点

//    public static void main (String[] args) throws IOException {
//        String fileFile = "D:\\phone\\";
//        int i = 300;
//        for (int i1 = 0; i1 < i; i1++) {
//            SliderCheck build = build();
//            String modifyImg = build.getModifyImg();
//            System.out.println(build.puzzleHeight + "," + build.getPuzzleWidth());
//            String newFileFile = fileFile + i1 + ".png";
//            GenerateImage(modifyImg, newFileFile);
//
//        }
//    }

    public static Captcha build(String pathName) {
        try {
            int[][] blockData = getBlockData();
            BufferedImage resourceImg = ImageIO.read(new File(pathName));

            //图片的长
            int width = resourceImg.getWidth();
            //图片的高
            int height = resourceImg.getHeight();
            //大图减小图的长，是图片可以移动的长度，避免
            int maxX = width - targetLength;
            //大图高减小图的高，是图片可以移动做大的高度
            int maxY = height - targetWidth;

            //可移动的距离设置成最长距离的1/4到3/4
            int x = new Random().nextInt(maxX / 2) + (maxX / 4);
            //可移动的高度设置成最长高度的1/4到3/4
            int y = new Random().nextInt(maxY / 2) + (maxY / 4);


            String resourceImgSt = getImageBASE64(resourceImg);
            BufferedImage puzzleImg = new BufferedImage(targetLength, targetWidth, BufferedImage.TYPE_4BYTE_ABGR);

            cutByTemplate(resourceImg, puzzleImg, blockData, x, y);

            String resourceUpImgSt = getImageBASE64(resourceImg);
            String puzzleImgSt = getImageBASE64(puzzleImg);

            Captcha captcha = new Captcha();

            captcha.setModifyImg(resourceUpImgSt);
            captcha.setPuzzleImg(puzzleImgSt);
            captcha.setyAxis(y);
            captcha.setxAxis(x);
            return captcha;
        } catch (Exception e) {
            logger.error("滑块图片验证码生成异常", e.getMessage());
            return null;
        }
    }

    public static String getImageBASE64(BufferedImage image) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ImageIO.write(image,"png",out);
        byte[] b = out.toByteArray();//转成byte数组
        BASE64Encoder encoder = new BASE64Encoder();
        return encoder.encode(b);//生成base64编码
    }

    /**
     *
     * @Createdate: 2019年1月24日上午10:52:42
     * @Title: getBlockData
     * @Description: 生成小图轮廓
     * @author mzl
     * @return int[][]
     * @throws
     */
    private static int[][] getBlockData() {

        int[][] data = new int[targetLength][targetWidth];
        double x2 = targetLength-circleR;

        //随机生成圆的位置
        double h1 = circleR + Math.random() * (targetWidth-3*circleR-r1);
        double po = circleR*circleR;

        double xbegin = targetLength-circleR-r1;
        double ybegin = targetWidth-circleR-r1;

        for (int i = 0; i < targetLength; i++) {
            for (int j = 0; j < targetWidth; j++) {
                double d3 = Math.pow(i - x2,2) + Math.pow(j - h1,2);
                double d2 = Math.pow(j-2,2) + Math.pow(i - h1,2);
                if ((j <= ybegin && d2 <= po)||(i >= xbegin && d3 >= po)) {
                    data[i][j] = 0;
                }  else {
                    data[i][j] = 1;
                }

            }
        }
        return data;
    }

    /**
     *
     * @Createdate: 2019年1月24日上午10:51:30
     * @Title: cutByTemplate
     * @Description: 生成小图片、给大图片添加阴影
     * @author mzl
     * @param oriImage
     * @param targetImage
     * @param templateImage
     * @param x
     * @param y void
     * @throws
     */
    private static void cutByTemplate(BufferedImage oriImage, BufferedImage targetImage, int[][] templateImage, int x, int y){
        for (int i = 0; i < targetLength; i++) {
            for (int j = 0; j < targetWidth; j++) {
                int rgb = templateImage[i][j];
                // 原图中对应位置变色处理
                int rgb_ori = oriImage.getRGB(x + i, y + j);

                if (rgb == 1) {
                    //抠图上复制对应颜色值
                    targetImage.setRGB(i, j, rgb_ori);
                    //原图对应位置颜色变化
                    oriImage.setRGB(x + i, y + j, rgb_ori & 0x363636 );
                }else{
                    //这里把背景设为透明
                    targetImage.setRGB(i, j, rgb_ori & 0x00ffffff);
                }
            }
        }
    }

    /**
     * 处理Base64解码并写图片到指定位置
     *
     * @param base64 图片Base64数据
     * @param path   图片保存路径
     * @return
     */
    public static boolean base64ToImageFile(String base64, String path) throws IOException {// 对字节数组字符串进行Base64解码并生成图片
        // 生成jpeg图片
        try {
            OutputStream out = new FileOutputStream(path);
            return base64ToImageOutput(base64, out);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return false;
    }
    /**
     * 处理Base64解码并输出流
     *
     * @param base64
     * @param out
     * @return
     */
    public static boolean base64ToImageOutput(String base64, OutputStream out) throws IOException {
        if (base64 == null) { // 图像数据为空
            return false;
        }
        try {
            // Base64解码
            byte[] bytes = org.apache.commons.codec.binary.Base64.decodeBase64(base64);
            for (int i = 0; i < bytes.length; ++i) {
                if (bytes[i] < 0) {// 调整异常数据
                    bytes[i] += 256;
                }
            }
            // 生成jpeg图片
            out.write(bytes);
            out.flush();
            return true;
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }



}
